﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using FreeX;


//TODO Implement ability to sort folders separately from files
//TODO Finish ability to choose details
//TODO provide for system context menu

namespace FileListView
{
    public partial class FileListview : UserControl
    {

        /// <summary>
        /// Constructor
        /// </summary>
        public FileListview()
        {
            InitializeComponent();
            history = new NavigationHistory();
        }

        #region Members

        private NavigationHistory history;
        private string m_InitialDirectory;

        /// <summary>
        /// Sets initial directory to load into FileListView
        /// </summary>
        public string InitialDirectory
        {
            get
            {
                return InitialDirectory;
            }
            set
            {
                m_InitialDirectory = value;
                history.Add(m_InitialDirectory);
                SetListviewAddress(m_InitialDirectory);

            }
        }


        /// <summary>
        /// the path currently pointed to by the FileListView control. Excludes the filename
        /// </summary>
        public string CurrentPath { get; set; }

        /// <summary>
        /// represents a list of all items currently selected in the FileListView
        /// </summary>
        public ListView.SelectedListViewItemCollection SelectedItems
        {
            get
            {
                return LstMain.SelectedItems;
            }
        }

        enum ListviewColumns
        {
            Name,
            Size,
            Type,
            [Description("Date Modified")]
            DateModified,
            [Description("Date Created")]
            DateCreated,
            Description,
            Attributes,
            Author,
            Owner,
            Title,
            Comments,
            Artist,
            [Description("Album Title")]
            AlbumTitle,
            Subject,
            Category,
            Pages,
            [Description("Date Accessed")]
            DateAccessed,
            Status,
            Copyright,
            Year,
            [Description("Track Number")]
            TrackNumber,
            Genre,
            Duration,
            BitRate
        }


        #endregion

        #region Designer Settings

        /// <summary>
        /// Represents the FileListView's display view
        /// </summary>
        [Browsable(true)]
        public View View
        {
            get
            {
                return LstMain.View;
            }

            set
            {
                LstMain.View = value;
            }
        }

        /// <summary>
        /// Specifies whether to sort directories separate from other items
        /// </summary>
        [Browsable(true), DefaultValue(true)]
        public bool SortDirectories
        {
            get; 
            set;
        }

        #endregion

        #region Events

        private void CboAddress_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                CurrentPath = CboAddress.Text;
                // Figure out if its a directory or a file // 
                //SetSelectedItemInformation(CurrentPath);
                var fi = new FileInfo(CurrentPath);
                if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    // Its a directory // 
                    LstMain.Items.Clear();
                    ShowDirectoriesInListView(CurrentPath);
                    ShowFilesInListView(CurrentPath);
                    /* add directory to the path history */
                    history.Add(CurrentPath);
                }
                else
                {
                    System.Diagnostics.Process.Start(CurrentPath);

                }
            }
        }

        private void CmdBack_Click(object sender, EventArgs e)
        {
            if (history.CanGoBack())
            {
                SetListviewAddress(history.GoBack());
            }
        }

        private void CmdForward_Click(object sender, EventArgs e)
        {
            if (history.CanGoForward())
            {
                SetListviewAddress(history.GoForward());
            }
        }

        private void CmdUp_Click(object sender, EventArgs e)
        {
            if (history.CanGoUp())
            {
                string up = history.GoUp();
                history.Add(up);
                SetListviewAddress(up);
            }
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            /* if there are no files on clipboard, disable paste menu item */
            ctxPaste.Visible = Clipboard.ContainsFileDropList();
        }

        private void ctxCut_Click(object sender, EventArgs e)
        {
            string[] files = new string[LstMain.SelectedItems.Count];

            for (int i = 0; i < LstMain.SelectedItems.Count; i++)
            {
                string filePath = Path.Combine(CurrentPath, LstMain.SelectedItems[i].Name);
                files[i] = filePath;
            }

            FreeXClipboard.Cut(files);
        }

        private void ctxCopy_Click(object sender, EventArgs e)
        {
            string[] files = new string[LstMain.SelectedItems.Count];

            for (int i = 0; i < LstMain.SelectedItems.Count; i++)
            {
                string filePath = Path.Combine(CurrentPath, LstMain.SelectedItems[i].Text);
                files[i] = filePath;
            }

            FreeXClipboard.Copy(files);
        }

        private void ctxPaste_Click(object sender, EventArgs e)
        {
            FreeXClipboard.Paste(CurrentPath);
            RefreshView();
        }

        private void ctxTileView_Click(object sender, EventArgs e)
        {
            LstMain.View = View.Tile;
        }

        private void ctxLargeIconView_Click(object sender, EventArgs e)
        {
            LstMain.View = View.LargeIcon;
        }

        private void ctxSmallIconView_Click(object sender, EventArgs e)
        {
            LstMain.View = View.SmallIcon;
        }

        private void ctxListView_Click(object sender, EventArgs e)
        {
            LstMain.View = View.List;
        }

        private void ctxDetailView_Click(object sender, EventArgs e)
        {
            LstMain.View = View.Details;
        }

        private void ItemActivate(object sender, EventArgs e)
        {

            // Figure out if its a directory or a file // 
            //SetSelectedItemInformation(CurrentPath);
            string selectedItemPath = Path.Combine(CboAddress.Text, SelectedItems[0].Text);
            var fi = new FileInfo(selectedItemPath);
            if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                // Its a directory // 
                LstMain.Items.Clear();
                ShowDirectoriesInListView(selectedItemPath);
                ShowFilesInListView(selectedItemPath);
                CboAddress.Text = selectedItemPath;
                CurrentPath = selectedItemPath;
                /* add directory to the path history */
                history.Add(CurrentPath);
                SetNavigationButtons();
            }
            else
            {
                System.Diagnostics.Process.Start(selectedItemPath);

            }

        }

        private void LstMain_SelectedIndexChanged(object sender, EventArgs e)
        {
            /* check to see if something is selected, then set ability to cut and copy */
            if (LstMain.SelectedItems.Count > 0)
            {
                ctxCopy.Visible = true;
                ctxCut.Visible = true;
                ctxDelete.Visible = true;
            }
            else
            {
                ctxCopy.Visible = false;
                ctxCut.Visible = false;
                ctxDelete.Visible = false;
            }
        }

        private void LstMain_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Create and/or configure the ListViewItemComparer to sort based on 
            // the column that was clicked.  
            var sorter = LstMain.ListViewItemSorter as ListViewSort;

            if (sorter == null)
            {
                // Create a new ListViewItemComparer. 
                sorter = new ListViewSort(e.Column);
                LstMain.ListViewItemSorter = sorter;
            }
            else
            {
                // Configure the existing ListViewItemComparer. 
                sorter.Column = e.Column;
            }

            // Sort the ListView 
            LstMain.Sort();

        }

        private void LstMain_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];

            /** set drag drop to cut or copy **/
            DragDropEffects dde = (e.KeyState & 4) == 4 ? DragDropEffects.Move : DragDropEffects.Copy;

            if (files != null)
                for (var i = 0; i < files.Length; i++)
                {
                    FreeXClipboard.Drop(CurrentPath, files[i], dde);
                }
            RefreshView();
        }

        private void LstMain_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;
        }

        private void LstMain_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {

                string[] files = new string[LstMain.SelectedItems.Count];
                int ctr = 0;

                foreach (ListViewItem item in LstMain.SelectedItems)
                {
                    string fullPath = Path.Combine(CurrentPath, item.Text);
                    files[ctr] = fullPath;
                    ctr++;
                }

                IDataObject data = new DataObject(DataFormats.FileDrop, files);
                LstMain.DoDragDrop(data, DragDropEffects.Copy);
            }
        }

        private void DeleteMenuItem_Click(object sender, EventArgs e)
        {
            if (File.Exists(CurrentPath))
            {
                File.Delete(CurrentPath);
                RefreshView();
            }
            else
            {
                MessageBox.Show("Selected fikle doesn't exist", "File Delete", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        #endregion

        #region Private Methods

        private void ShowDirectoriesInListView(string thePath)
        {
            var dir = new DirectoryInfo(thePath);

            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {
                var it = new ListViewItem(subDir.Name, 0);
                FillDirectoryDetails(subDir, it);
            }

        }

        private void ShowFilesInListView(string thePath)
        {

            ListViewItem it;
            var dir = new DirectoryInfo(thePath);

            LstMain.BeginUpdate();

            /* go through and show the directories */
            Image ic = FolderList.Images[0];

            /* add icon froom shell into image lists */
            LargeImageList.Images.Add(ic);
            SmallImageList.Images.Add(ic);

            try
            {
                // loop through all file in the selected directory // 
                foreach (FileInfo f in dir.GetFiles())
                {
                    var ffi = new FreeXFileInfo(Path.Combine(CurrentPath, f.Name));
                    // depending on the view, set the appropriate icon size and details // 
                    string itemToolTip;
                    if (LstMain.View == View.LargeIcon)
                    {

                        // this bit extracts the associated icon from the shell // 
                        LargeImageList.Images.Add(ffi.AssociatedIconLarge);
                        it = new ListViewItem(ffi.Filename, LargeImageList.Images.Count - 1);

                        // Set the tooltip with info 
                        itemToolTip = "Type: " + ffi.FileType + "\rSize: " + ffi.GetFormattedFileSize(FreeXFileInfo.FileSizeFormat.Auto);
                        it.ToolTipText = itemToolTip;

                        // add the item 
                        LstMain.Items.Add(it);
                    }
                    else if (LstMain.View == View.SmallIcon)
                    {
                        SmallImageList.Images.Add(ffi.AssociatedIconSmall);
                        it = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
                        LstMain.Items.Add(it);
                        // Set the tooltip with info 
                        // Set the tooltip with info 
                        itemToolTip = "Type: " + ffi.FileType + "\rSize: " + ffi.GetFormattedFileSize(FreeXFileInfo.FileSizeFormat.Auto);
                        it.ToolTipText = itemToolTip;
                    }
                    else
                    {
                        SmallImageList.Images.Add(ffi.AssociatedIconSmall);
                        //it = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
                        // Use this to get all of the file info // 
                        FillFileDetails(ffi);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Data.ToString(), "Error");
            }

            /* A couple of ListView setting */
            LstMain.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
            LstMain.EndUpdate();
        }

        private void FillDirectoryDetails(FileSystemInfo thePath, ListViewItem theItem)
        {

            var size = new ListViewItem.ListViewSubItem(theItem, "");
            var type = new ListViewItem.ListViewSubItem(theItem, "Directory");

            var createDate = new ListViewItem.ListViewSubItem(theItem, thePath.CreationTime.ToShortDateString());
            var modDate = new ListViewItem.ListViewSubItem(theItem, thePath.LastWriteTime.ToShortDateString());
            var accessedDate = new ListViewItem.ListViewSubItem(theItem, thePath.LastAccessTime.ToShortDateString());
            var description = new ListViewItem.ListViewSubItem(theItem, string.Empty);
            var attributes = new ListViewItem.ListViewSubItem(theItem, thePath.Attributes.ToString());


            theItem.SubItems.Add(size);
            theItem.SubItems.Add(type);
            theItem.SubItems.Add(createDate);
            theItem.SubItems.Add(modDate);
            theItem.SubItems.Add(accessedDate);
            theItem.SubItems.Add(description);
            theItem.SubItems.Add(attributes);

            LstMain.Items.Add(theItem);

        }

        private void FillFileDetails(FreeXFileInfo ffi)
        {
            var theItem = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
            var size = new ListViewItem.ListViewSubItem(theItem, ffi.GetFormattedFileSize(FreeXFileInfo.FileSizeFormat.Auto));
            var type = new ListViewItem.ListViewSubItem(theItem, ffi.FileType);

            var createDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateCreated.ToShortDateString());
            var modDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateModified.ToShortDateString());
            var accessedDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateLastAccessed.ToShortDateString());
            var description = new ListViewItem.ListViewSubItem(theItem, ffi.Description);
            var attributes = new ListViewItem.ListViewSubItem(theItem, ffi.Attributes);

            var comments = new ListViewItem.ListViewSubItem(theItem, ffi.Comments);
            var copyRight = new ListViewItem.ListViewSubItem(theItem, ffi.Copyright);

            ListViewItem.ListViewSubItem dimensions;
            ListViewItem.ListViewSubItem height;
            ListViewItem.ListViewSubItem width;
            ListViewItem.ListViewSubItem vRes;
            ListViewItem.ListViewSubItem hRes;

            if (ffi.FileExtension.ToLower() == ".gif" || ffi.FileExtension.ToLower() == ".png" || ffi.FileExtension.ToLower() == ".bmp")
            {
                dimensions = new ListViewItem.ListViewSubItem(theItem, "");
                height = new ListViewItem.ListViewSubItem(theItem, ffi.Height.ToString());
                width = new ListViewItem.ListViewSubItem(theItem, ffi.Width.ToString());
                vRes = new ListViewItem.ListViewSubItem(theItem, ffi.VerticalResolution.ToString());
                hRes = new ListViewItem.ListViewSubItem(theItem, ffi.HorizontalResolution.ToString());
            }
            else
            {
                dimensions = new ListViewItem.ListViewSubItem(theItem, "");
                height = new ListViewItem.ListViewSubItem(theItem, "");
                width = new ListViewItem.ListViewSubItem(theItem, "");
                vRes = new ListViewItem.ListViewSubItem(theItem, "");
                hRes = new ListViewItem.ListViewSubItem(theItem, "");
            }

            theItem.SubItems.Add(size);
            theItem.SubItems.Add(type);
            theItem.SubItems.Add(createDate);
            theItem.SubItems.Add(modDate);
            theItem.SubItems.Add(accessedDate);
            theItem.SubItems.Add(description);
            theItem.SubItems.Add(attributes);

            theItem.SubItems.Add(comments);
            theItem.SubItems.Add(copyRight);
            theItem.SubItems.Add(dimensions);
            theItem.SubItems.Add(height);
            theItem.SubItems.Add(width);
            theItem.SubItems.Add(vRes);
            theItem.SubItems.Add(hRes);
            LstMain.Items.Add(theItem);
            // Set the tooltip with info 
            string itemToolTip = "Type: " + ffi.FileType + "\rSize:" + ffi.GetFormattedFileSize(FreeXFileInfo.FileSizeFormat.Auto);
            theItem.ToolTipText = itemToolTip;

        }

        private void SetNavigationButtons()
        {
            /** set the buttons accordingly **/
            CmdBack.Enabled = history.CanGoBack();

            CmdForward.Enabled = history.CanGoForward();

            CmdUp.Enabled = history.CanGoUp();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Handles loading the listview with the currently selected path
        /// </summary>
        /// <param name="path">the path to set the control to</param>
        public void SetListviewAddress(string path)
        {
            /* using getFullPath to clean the path string */
            CboAddress.Text = Path.GetFullPath(path);
            CurrentPath = CboAddress.Text;
            ShowDirectoriesInListView(path);
            ShowFilesInListView(path);

            SetNavigationButtons();
        }

        /// <summary>
        /// Reloads the current path into the FileView
        /// </summary>
        public void RefreshView()
        {
            ShowFilesInListView(CurrentPath);
        }

        /// <summary>
        /// NOT YET IMPLEMENTED
        /// </summary>
        /// <param name="index">index of column to manipulate</param>
        /// <param name="visible">true to show column, false to hide it</param>
        public void SetColumnVisible(int index, bool visible)
        {
            if (visible)
            {
                LstMain.Columns.Insert(index, LstMain.Columns[index].Text);
            }
            else
            {
                LstMain.Columns.RemoveAt(index);
            }
        }

        #endregion



    }
}